package isjinhao.jlox.grammar.expression;

import isjinhao.jlox.grammar.Parser;
import isjinhao.jlox.lexical.TokenSequence;
import isjinhao.jlox.grammar.expression.represention.*;
import isjinhao.jlox.lexical.Token;
import isjinhao.jlox.lexical.TokenType;

/**
 * @Author ISJINHAO
 * @Date 2021/2/24 17:23
 */
public class ExpressionParser extends Parser<Expression> {

    public ExpressionParser(TokenSequence tokenSequence) {
        super(tokenSequence);
    }

    /**
     * primary      ->  "nil" | NUMBER | STRING | "true" | "false" | "(" expression ")"
     * unary        ->  ("!" | "-") unary | primary
     * arithmetic   ->  unary (("+" | "-" | "*" | "/") unary)*
     * comparison   ->  arithmetic ((">" | "<" | ">=" | "<=" | "!=" | "==") arithmetic)?
     * logic        ->  comparison (("or" | "and") comparison)*
     * expression   ->  logic
     */
    @Override
    public Expression parse() {
        return expression();
    }

    protected Expression expression() {
        return logic();
    }

    protected Expression logic() {
        Expression left = comparison();
        while(tokenSequence.curEqual(TokenType.OR, TokenType.AND)) {
            Token token = tokenSequence.takeCur();
            tokenSequence.advance();
            Expression right = comparison();
            left = new Logic(left, token, right);
        }
        return left;
    }

    protected Expression comparison() {
        Expression left = arithmetic();
        if (tokenSequence.curEqual(TokenType.GREATER, TokenType.GREATER_EQUAL,
                TokenType.LESS, TokenType.LESS_EQUAL,
                TokenType.BANG_EQUAL, TokenType.EQUAL_EQUAL)) {
            Token operator = tokenSequence.takeCur();
            tokenSequence.advance();
            Expression right = arithmetic();
            return new Comparison(left, operator, right);
        }
        return left;
    }

    protected Expression arithmetic() {
        Expression expression = unary();
        while (tokenSequence.curEqual(TokenType.PLUS, TokenType.MINUS,
                TokenType.STAR, TokenType.SLASH)) {
            Token operator = tokenSequence.takeCur();
            tokenSequence.advance();
            Expression right = unary();
            expression = new Arithmetic(expression, operator, right);
        }
        return expression;
    }

    /**
     * 语法：(("!" | "-") unary) | primary
     * 不能使用：("!" | "-")* primary。因为这种写法不能使用递归下降。
     */
    protected Expression unary() {
        // "!-123"是不符合语法规则的。但我们将这个问题推迟到运行时检测。
        if (tokenSequence.curEqual(TokenType.BANG, TokenType.MINUS)) {
            Token operator = tokenSequence.takeCur();
            tokenSequence.advance();
            return new Unary(operator, unary());
        }
        return primary();
    }

    protected Expression primary() {
        if (tokenSequence.curEqual(TokenType.FALSE)) {
            tokenSequence.advance();
            return new Literal(false);
        }
        if (tokenSequence.curEqual(TokenType.TRUE)) {
            tokenSequence.advance();
            return new Literal(true);
        }
        if (tokenSequence.curEqual(TokenType.NIL)) {
            tokenSequence.advance();
            return new Literal(null);
        }
        if (tokenSequence.curEqual(TokenType.NUMBER, TokenType.STRING)) {
            tokenSequence.advance();
            return new Literal(tokenSequence.takePre().getLiteral());
        }
        if (tokenSequence.curEqual(TokenType.LEFT_PAREN)) {
            tokenSequence.advance();
            Expression expression = expression();
            tokenSequence.consume(TokenType.RIGHT_PAREN, "Expect ')' after expression.");
            return new Grouping(expression);
        }
        throw tokenSequence.error(tokenSequence.takeCur(), "Expect expression.");
    }

}
